package com.xianggu.lock;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;

/**
 * @author chengjy
 * @date 2025/3/19
 */
public class XiangGuReentryLock implements Lock{

    // 重入锁
    private volatile AtomicInteger state = new AtomicInteger(0);
    // 需要头结点是因为唤醒从头开始唤醒
    private AtomicReference<Node> head = new AtomicReference<>(new Node(null, null));
    // 需要尾结点是因为排队从后排
    private AtomicReference<Node> tail = new AtomicReference<>(head.get());

    private Thread currentThread;

    // 加锁
    @Override
    public void lock() {
        // 判断是否可以获取锁
        if (state.compareAndSet(0, 1)) {
            // 设置当前线程为持有锁线程
            this.currentThread = Thread.currentThread();
            System.out.println("a、线程" + Thread.currentThread().getName() + "获得了锁");
            return;
        } else if (this.currentThread == Thread.currentThread()) {
            if (state.compareAndSet( state.get() , state.get() + 1)) {
                System.out.println("a2、线程" + Thread.currentThread().getName() + "获得了重入锁：" + state.get());
                return;
            }
        }
        // 一直尝试知道将当前节点加入尾结点
        Node current = new Node(tail.get(), Thread.currentThread());
        while (true) {
            Node currentTail = tail.get();
            if (tail.compareAndSet(currentTail, current)) {
                current.pre = currentTail;
                currentTail.next = current;
                System.out.println("b、线程" + Thread.currentThread().getName() + "加入等待队列");
                break;
            }
        }
        // 判断是否虚假唤醒（只有头结点的下个节点为在自己、且持锁状态修改返回true才可退出阻塞、执行资源方法）

        while (true) {
            if (head.get().next == current && state.compareAndSet(0, 1)) {
                // 设置当前线程为持有锁线程
                this.currentThread = Thread.currentThread();
                // 将自己设置为头节点
                current.pre = null;
                head.get().next = null;
                head.set(current);

                System.out.println("a、线程" + Thread.currentThread().getName() + "获得了锁");
                return;
            }
            // 阻塞线程
            LockSupport.park();
        }
    }

    // 释放锁
    @Override
    public void unlock() {
        if (this.currentThread == Thread.currentThread()) {
            state.compareAndSet(state.get(), state.get() - 1);
            // 判断此时是否需要重新释放锁，只有state为0才能释放锁
            Node currentHead = head.get();
            if (state.get() == 0 && currentHead.next != null) {
                LockSupport.unpark(currentHead.next.thread);
            }
            // 结束方法
        } else {
            throw new RuntimeException("当前线程未持有锁");
        }

    }


}
